package com.atguigu.gulimall.order;

import com.atguigu.gulimall.order.entity.OrderEntity;
import com.atguigu.gulimall.order.entity.OrderReturnReasonEntity;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

import javax.xml.bind.SchemaOutputResolver;
import java.io.IOException;


/**
 * 使用RabbitMQ
 * 1、引入 spring-boot-starter-amqp 启动器，RabbitAutoConfiguration就会自动生效
 *
 * 2、给容器中自动配置了
 *      RabbitTemplate、AmqpAdmin、CachingConnectionFactory 等bean
 *
 *    配置文件中
 *    spring:
 *      rabbitmq:
 *        host: 121.40.182.123
 *        port: 5672   #RabbitMQ客户端需要连接的端口
 *        virtual-host: /
 *
 * 3、@EnableRabbit
 *
 * 4、监听消息：使用@RabbitListener, 必须有@EnableRabbit 才能使用
 *      @RabbitListener： 类 + 方法
 *      @RabbitHandler :  标注在方法上，用来区分不同的消息
 *
 *
 * 5、使用Seata控制分布式事务
 *      1） 每一个微服务关联的数据库必须先创建undo_log表
 *      2） 安装事务协调器TC：seata-server  https://github.com/seata/seata/releases
 *      3） springboot整合seata
 *          1、导入依赖 ：spring-cloud-starter-alibaba-seata
 *          2、启动seata-server
 *              config/registry.conf: 注册中心配置    修改成type=nacos
 *          3、所有想要用到分布式事务的微服务，都需要使用seata代理自己的数据源
 *          4、每个服务都必须导入 register.conf和file.conf
 *                  file.conf ： vgroup_mapping.{application.name}-fescar-service-group = "default"
 *
 *          5、给分布式大事务的入口标注 @GlobalTransactional
 *             每一个远程的小事务标注 @Transactional
 *
 */
@EnableFeignClients
@EnableRedisHttpSession
@EnableRabbit
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallOrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallOrderApplication.class, args);
    }


    /*
    接收消息

            参数可以写一下类型
            1、Message message : 原生消息详细信息 消息头 + 消息体
            2、T<发送的消息的类型> t
            3、Channel channel ： 当前传输数据的通道

            【注意】
               Queue: 一个Queue可以很多个客户端来监听，只要有一个客户端收到消息，Queue就会删除消息，有且仅有一个客户端会接收到消息

               场景：
               1、当订单服务启动多个时，发出一个消息时，有且仅有一个客户端会收到消息
               2、一个客户端，只有当一个消息处理完，才会接受另一个消息

     */
    @RabbitListener(queues = {"hello-java-queue"})
    public void receiveMessage(Message message, OrderReturnReasonEntity content, Channel channel){
        System.out.println("接收到消息：" + content);
        //channel内按顺序递增的
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        // deliveryTag: 消息投递标签   multi: 是否批量确认
        try {
            if(deliveryTag%2==0){
                System.out.println("手动签收");
                //参数： long deliveryTag,boolean multiple
                channel.basicAck(deliveryTag,false);
            }else{
                System.out.println("拒绝签收");
                //参数  ： long deliveryTag,boolean multiple,boolean require
                //require = false : 直接将该消息丢弃    require = true: 将该消息发回服务器，服务器重新入队
                channel.basicNack(deliveryTag,false,false);
                //channel.basicReject();
            }
        } catch (IOException e) {
            //网络中断
            e.printStackTrace();
        }
    }

}
